﻿using System;
using System.Linq;
using IGS.Core.Models;
using NUnit.Framework;

namespace IGS.Core.Tests.Models
{
    public static class PlummerModelTests
    {
        [TestFixture]
        public class GivenOnePlummerModel
        {
            [Test]
            public void WhenGenerateIsCalledThenAnNBodySystemShouldBeCreated()
            {
                // Arrange
                const int n = 1024;
                const double totalMass = 1.0;
                const double plummerRadius = 1.0;
                var model = new PlummerModel();

                // Act
                var system = model.Generate(n, totalMass, plummerRadius);

                // Assert
                Assert.IsNotNull(system, "System");
                Assert.AreEqual(n, system.Length, "System.Length");
            }

            [Test]
            public void WhenGenerateIsCalledThenTheNBodySystemShouldHaveAPlummerMassDistribution()
            {
                // Arrange
                const int n = 10000;
                const double totalMass = 1.0;
                const double plummerRadius = 1.0;
                var model = new PlummerModel();

                // Act
                var system = model.Generate(n, totalMass, plummerRadius);

                var bodies = system.OrderBy(b => b.Position.Length).ToList();

                var cumulativeMass = 0.0;
                foreach (var body in bodies)
                {
                    cumulativeMass += body.Mass;
                    var r = body.Position.Length;

                    var expectedMass = totalMass * (r * r * r) / Math.Pow(r * r + plummerRadius * plummerRadius, 1.5);

                    // Assert
                    const double delta = 1.0 / n;
                    Assert.AreEqual(expectedMass, cumulativeMass, delta, "M({0})", r);
                }
            }
        }
    }
}
